#include <stdio.h>
/* Pascal Trebert */

void printschein(int s);
char** charfunc(char * cp);
int i = 9;

char **charfunc(char*cp){
  return NULL;
}


void gibaus(int (*a)[5]){ /* int a[][5] */
  int i, j;
  for (i=0; i< 3; i++){
    for(j=0; j<5; j++){
      printf("%2d ", a[i][j]);
    }
      printf("\n");
  }
}
void definiere()
{
  char *str1 = "Hallo";
  char *str2 = "Ho";
  char * cparr[3][3][3];
  cparr[0][0][0] = str1; /* string ausgabe %s erwartet ADRESSE keine Dereferenzierung, das wäre nur ein char */
  cparr[0][0][1] = str2;
  printf("cparr[0][0][0]:\t%s\ncparr[0][0][1]:\t%s\n", cparr[0][0][0], cparr[0][0][1]);
  

  unsigned long l0 = 0;
  unsigned long l1 = 1;
  unsigned long l2 = 2;
  unsigned long *pa[3] = {l0, l1, l2};

  double dv[3] = { 1.0, 2.0, 3.0 };
  double (*pd)[3] = &dv;
  
  char c;
  char *pc = &c;
  char **ppc = &pc;
  char **x[3][2];
  char **(*px)[3][2] = &x;
  
  c = 'a';
  *pc = 'a';
  **ppc = 'a';
  x[0][1] = ppc;
  **(*px)[0][1] = 'b'; /* klammern vorrang! erst (*px) dann [0][1] dann 2mal dereferenzieren */
  

  char *s1 = "Hallo";
  char *s2 = "Du";
  char *s3 = "freak";
  char * arr[] = {s1, s2, s3};
  int i;
  for(i=0; i<3; i++){
    printf("arr[i]:\t%s\n", *(arr+i));
  }


  int a1[3][5] = { {0,1,2,3,4},
		   {5,6,7,8,9},
		   {10,11,12,13,14}
  };
  gibaus(a1);

  int a2[][5] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14};
  gibaus(a2);

  char a3[5] = {1,2,3};
  printf("a3:\t%2d %2d %2d %2d %2d \n", a3[0], a3[1], a3[2], a3[3], a3[4]);

  int a4[] = {1,2,3};
  printf("sizeof a4:\t%u\n", sizeof a4);

/* definieren Sie */

 /* z1 als 4x4 array von char */
   char z1[4][4];
   
/* z2 als pointer auf ein 4x4 Array von char und initialisieren sie es mit z1 */
   char  (*z2)[4][4] = &z1;

   /* z3 als pointer auf 2. zeile 3. spalte des vorigen arrays indem sie z1 benutzen und setzen sie das char 'J' */
   char *z3 = &z1[1][2];
   *z3 = 'J';
   printf("*z3:\t%c\n", *z3);
/* z4 als poitner auf 2. zeile 3. spalte des vorigen arrays indem sie pointer z2 benutzen */
   char *z4 = &(*z2)[1][2];
   printf("*z4:\t%c\n", *z4);
   
   /* z5 als array von double werten 4.5, 5.6 , 6.6 */
   double z5[] = {4.5, 5.6, 6.6};
   printf("z5[0]:\t%lf\n", z5[0]);
   printf("*z5:\t%lf\n", *z5);
   printf("*(z5+1):\t%lf\n", *(z5+1));
   printf("*(z5+2):\t%lg\n", *(z5+2));

/* z6 als konstanten zeige r auf z5 */
   double (* const z6) [3] = &z5;
   printf("z6[0]:\t%lf\n", z6[0]);

/* z7 als 3D Array von Zeigern auf double */
   double * z7[4][4][4];
   double dz7 = 1.1;
   z7[1][1][1] = &dz7;
   printf("*z7[1][1][1]:\t%lg\n", *z7[1][1][1]);
   
/* z8 als constanten Zeiger auf ein 3D Array P6 */
   double * (* const z8)[4][4][4] = &z7;
   printf("*(*z8)[1][1][1]:\t%lg\n", *(*z8)[1][1][1]);

/* z9 als zeiger auf eine funktion die char** als rückgabe und char* als Parameter hat */
   char**  (*z9)(char*); /* die parameter können ohen variable geschrieben werden bei der definition oder auch mit (char * c) */

/* z10 als konstanten Zeiger auf ein gegebenes int ii */
   int ii = 10;
   int * const z10 = &ii;
   printf("*z10:\t%d\n", *z10);

   /* z11 als zeiger auf ein gegebenens konstantes int jj; */
   const int jj = 11;
   const int * z11 = &jj;
   printf("*z11:\t%d\n", *z11);

/* z12 als konstanten zeiger auf ein gegebenes konstantes int ij */
   const int ij = 12;
   const int * const z12 = &ij;
   printf("*z12:\t%d\n", *z12);
/* man kann auch auf nicht konstante variablen einen konstanten pointer setzen oder sagen dass der pointer den wert nicht ändern kann */
   int k = 13;
   const int * const zk = &k;
   printf("*zk:\t%d\n", *zk);

/* p1 als ein 4x4 Array von char */
  char p1 [4][4] = {{'A', 'a', 'b', 'c'},
		    {'B'},
		    {'C'},
		    {'D'}
  };

/* p2 als Pointer auf ein 4x4 Array von char und initialisiern sie s mit p1 */
  char (*p2)[4][4] = &p1;
  printf("(*p2)[0][0]:\t%d\n", (*p2)[0][0]); /* einzigst richtige moeglichkeit p2 zum indizieren zu benutzen */
  
/* /\*   p3 als pointer auf auf position (2,3) des vorigne 4x4 Arrays indem sie p2 benutzen *\/ */
  char *p3 = &((*p2)[2][3]);
  *p3 = 'P';
  printf("*p3:\t%c\n", *p3);
  printf("(*p2)[2][3]:\t%c\n", (*p2)[2][3]);

  /* pp3 als pointer auf die position (2,3) des arrays indem sie p1 benutzen */
  char *pp3 = &p1[2][3];
  printf("*pp3:\t%c\n", *pp3); /* ich will wirklich das zeichen haben also muss ich den pointer noch dereferenzieren (so oft wie * am pointer sindb) */
  
/* p33 als pointer auf die 2. Zeile 3. Spalte im array p1 mit hilfe des pointers p2 und setzen sie dann mit p33 ein 'Q' an diese stelle. */
  char *p33 = &((*p2)[1][2]);
  *p33 = 'Q';
  printf("*p33:\t%c\n", *p33);
  printf("p1[1][2]:\t%c\n", p1[1][2]);

  int j;
  for(i=0; i<4; i++){
    for(j=0; j<4;j++){
      if(p1[i][j] == 0){
	printf("%d ", p1[i][j]);
      }
      else{
	printf("%c ", p1[i][j]);
      }
    }
    printf("\n");
  }

/* p4  als array von 3 Double Werten 4.5, 5.6, 6.6 */
  double p4[] = {4.5, 5.6, 6.6};
  printf("p4[0]:\t%lf\n", p4[0]);

/* p5 als konstanten Zeiger auf p4. */
  double (* const p5)[3] = &p4;
  printf("(*p5)[2]:\t%lg\n", (*p5)[2]);
  printf("*(p5+3):\t%lg\n", *(p5+3));

/* p6 als 3-D array von Zeigern auf double und setzen Sie an der Stelle [0][0][3] einen pointer auf den Wert 4.4 */
  double * p6[4][4][4];
  double d = 4.4;
  p6[0][0][3] = &d;
  printf("*(p6[0][0][3]):\t%lf\n", *(p6[0][0][3]));

/* p7 als constanten Zeiger auf 3 Dimensionales array p6 */
  double * (* const p7) [4][4][4] = &p6;
  printf("*((*p7)[0][0][3]):\t%lg\n", *((*p7)[0][0][3]));

/* p8 als Zeiger auf die vorhandene Funktion charfunc, die char** als rückgabe und char* als Parameter hat */
  char ** (*p8)(char * cp) = charfunc;
  printf("&p8:\t:%p\n", &p8);
/* p81 als Zeiger auf die Fukntion gibaus die ein 2Dimensionales int Array mit 5 Spalten erwartet */
  void (*p81)(int [][5]) = gibaus;
  printf("p81(a1):\n");
  p81(a1);

/* P9 als Konstanten Zeiger auf gegebenes int i */
  int * const p9 = &i;
  printf("*p9:\t%i\n", *p9);

/* p10 als char */
  char p10 = 'C';
  printf("p10:\t%c\n", p10);

/* p11 als pointer auf ein char und initialisieren sie so dass ihn auf p10 zeigt */
  char *p11 = &p10;
  printf("*p11:\t%c\n", *p11);

/* p12 als pointer auf pointer auf ein char und lassen sie ihn auf p11 zeigen */
  char **p12 = &p11;
  printf("**p12:\t%c\n", **p12);

/* p13 als 2x3 Array (2 breit 3 hoch) von char pointern auf char pointer (kleine Kiste auf kleine Kiste) */
  char ** p13[3][2] = {{0}}; /* initialisieren wichtig glaube ich, mit doppelten Klammern sicherer */
  
  /* ps13 als char Array mit dem String "hi"  */
  /* ps13 ist ein konstanter Pointer auf die Zeichenkette "hi" */
  char  ps13 [] = "hi";
  printf("ps13:\t%s\n", ps13);

  /* einen pointer pss13 der auf die selbe Zeichenkette "hi" zeigt */
  char *pss13 = ps13; 
  printf("pss13:\t%s\n", pss13);
 
  /* und ppps13 als pointer auf den konstanten pointer ps13 */
  char ** ppps13 = &ps13;
  printf("ppps13:\t%s\n", ppps13); /* achtung bei Ausgabe muss ich mehr dereferenzieren da ps13 schon an der speicherstelle steht vom 1. Zeichen */

  /* pps13 als pointer auf den pointer pss13 */
  char ** pps13 = &pss13; 
  printf("*pps13:\t%s\n", *pps13); /* hier muss ich dereferenzieren, es reicht bis zu dem pointer der auf ein char zeigt zu dereferenzieren, fuer die string ausgabe */

  /* eigentlich logisch will ich das char selbst muss ich sooft dereferenzieren wie ** am pointer sind den ich nehme */
  printf("**pps13:\t%c\n", **pps13);

/* das array p13 soll an der 1. Zeile 1.Spalte auf den pointer pss13 zeigen */
  p13[0][0] = &pss13; 
 /* normale zuweisung mit arraynamen kein problem, willb dass stelle 0,0 auf den pointer *ps13 zeigt */
  printf("p13[0][0]:\t%p und die adresse des pointers *ps13 ist:%p\n", p13[0][0], &ps13);

  /* benutzen sie p13 und aendern sie den String 'hi' auf 'ho' */
  *(*p13[0][0]+1) = 'o';
  printf("*p13[0][0]:\t%s\n", *p13[0][0]);
  /* besser immer richtige poitner auf Zeichenketten machen, die konstanten pointer verhalten sich unangenehm */

/* p14 als als pointer auf ein 2x3 (2 breit 3 hoch) array von pointer auf pointer auf char und lassen sie ihn auf p13 zeigen */
  char **  (*p14)[3][2] = &p13;
  
  /* benutzen sie p14 und fugen sie an der stelle 3. Zeile 2. Spalte einen Pointer pp14 auf den pointer ps14 auf den  String "hallo" ein */
  char * ps14 = "hallo";
  char **pp14 = &ps14;
  (*p14)[2][1] = pp14;
  printf("*(*p14)[2][1]:\t%s\n", *(*p14)[2][1]); /* habe ich pointer auf pointer auf char, reicht es einmal zu dereferenzieren für stringausgabe (adresse 1. Zeichen) */

/* ppp14 als Zeiger auf die stelle 3. Zeile 2. Spalte des array ziegers p14. */
  char ***ppp14 = &((*p14)[2][1]);
  printf("**ppp14:\t%s\n", **ppp14); /* zweimal dereferenzieren holt mir den pointer auf die zeichenkette  */

/* Was ist die Ausgabe? */
  

  /* p14[2][2] = &p10; */
  /* **(*p14)[3][2] = 'b' */
  
  /* printf("c = %c\n", p10); */
  /* printf("c = %c\n", *p11); */
  /* printf("c = %c\n", **p12); */
  /* printf("c = %c\n", p10[0][1]); */
  /* printf("c = %c\n", **(*p14)[2][2]); */
  /* printf("c = %c\n", p14[3][2]); */

/* Was wird ausgegeben ? */
  /* char *c[] = {"ENTER", "NEW", "POINT", "FIRST"}; */
  /* char **cp = { c+3, c+2, c+1, c}; */
  /* char ***cpp = cp; */
  
  /* printf("%s", **++cpp); */
  /* printf("%s", *--*++cpp+3); */
  /* printf("%s", *cpp[-2]+3); */
  /* printf("%s\n", cpp[-1][-1]+1);  */

/* Definieren Sie */
/* p15 als Zeiger auf Zeiger auf char */
/* p16 als Zeiger auf Vektor mit Platz fuer 13 int */
/* p17 als Vektor mit Platz fuer 13 Zeiger auf int  */
/* p18 als Funktion die void zurueck gibt */
/* p19 als Zeiger auf auf eine Funktion die void zurueck gibt und sie soll auf p18 zeigen */
/* p20 als Funktion mit Resultat Zeiger auf Vektor mit Zeiger auf Funktion die char zurueck gibt */
/* p21 als 3 Elementigen Vektor mit Zeiger auf Funktion mit Resultat Zeiger auf 5 Elementigen Vektor von char */

/* Deklarieren Sie */
/*     zeiger auf vektor */
/*     vektor mit zeigern */
/*     zeiger auf funktion */
/*     zeiger z1 auf eine Funktion f1 , die int zurückgibt und einen char als param hat */
/*     zeiger z2 auf funktion f2 , die char** als rückgabe und char* als param hat */
/*     konstanten zeiger z3 auf ein int Wert i1 */
/*     Pointer auf 3-Dim, 4-Dim Arrays, */
/*     Pointer auf 3 dimensionales array aus zeigern */
/*     typedef mit namen grusstyp vom typ pointer auf eine Funktion die ein char* zurück gibt und void erwartet */
/*     anschliessend einen pointer des selben typs mit namen gruss */
/*     typedef fuer int mit namen ganzzahl */
/*     typedef für ein enum {rot|gruen|gelb} mit Namen ampelfarben */
/*     definieren sie einen eigenen Typ mit namen knotenzeiger der ein Pointer auf ein struct _knoten ist */
/*     definieren sei einen eigenen Typ mit namen knoten das ein struct ist und ein Element des vorigen typs knotenzeiger hat das next heißt und eins vom typ ganzzahl was data heißt */
/*     legen sie zwei Knoten an mit hilfe des neuen Typs knoten */
/*     legen sie je knoten einen Zeiger auf ihn an, benutzen sie den knotenzeiger */
/*     verketten sie die beiden Knoten dass n1 mit next auf n2 zeigt  */

/* Initialisieren Sie */

/*     zeiger auf vektor */
/*     vektor mit zeigern */
/*     zeiger auf funktion */
/*     zeiger z1 auf eine Funktion f1 , die int zurückgibt und einen char als param hat */
/*     zeiger z2 auf funktion f2 , die char** als rückgabe und char* als param hat */
/*     konstanten zeiger z3 auf ein int Wert i1 */
/*     Pointer auf 3-Dim, 4-Dim Arrays, */
/*     Pointer auf 3 dimensionales array aus zeigern  */


/* Legen Sie an */

/*     Char Array mit 4x4 Matrix */
/*     Pointer auf das Array */
/*     Pointer auf Positionen (3,4) und (4,1) im Array  */

       /*  zeiger z1 auf eine Funktion f1 , die int zurückgibt und einen char als param hat */
    /*     zeiger z2 auf funktion f2 , die char** als rückgabe und char* als param hat */
    /*     konstanten zeiger z3 auf ein int Wert i1  */

    /* initialisiere */
    /*     den Zeiger auf die Funktion */
    /*     den Zeiger auf den int  */



}

void bit()
{
  int sl=3, sr=2;
  
  int a = 4, b = 7;
  /* int a = 7, b = 4; */
  /* int a = 4, b = 9; */
  /* int a = 2, b = 1; */
  /* int a = 10, b = 6; */
  printf("%d", a & b);
  printf("%d", a|b);
  printf("%d", a^b);
  printf("%d", ~(~a&~b));
  printf("%d", a<<sl);
  printf("%d\n", a>>sr);
  
} 
/*  enum Scheine { Prog1=1<<0, Prog2=1<<1, */
/* 		Prog3=1<<2, ADS = 1<<3, */
/* 		Theo= 1<<4}; */
 
/*  enum Scheine susi = Prog1|Prog2|Theo; */
/*  int rudi = Prog1|Prog3|ADS; */
/*  printschein(susi); */
/*  printschein(rudi); */
/*  printschein(susi | rudi); */
/*  printschein(susi & rudi); */
/*  printschein(~susi); */
/* }    */
/* void printschein(int s) { */
/*   if (s & Prog1) printf("Prog1 "); */
/*   if (s & Prog2) printf("Prog2 "); */
/*   if (s & Prog3) printf("Prog2 "); */
/*   if (s & ADS) printf("ADS "); */
/*   if (s & Theo) printf("Theo "); */
/*   printf("\n"); */
/* } */

int zeichen(char *s1, char *s2){
  int z=0;
  char last = '\0';
  while(*s1 != '\0'){
    last = *s1;
    s1++;
  }
  while(*s2 != '\0'){
    if(*s2 == last){
      z++;
    }
      s2++;
  }
  return z;
}

void funktionen()
{
  char * s1 = "HiHiHi";
  char *s2 = "Hahihiho";

  int z = zeichen(s1, s2);

  printf("s1: %s\ns2%s\n%d\n", s1, s2,  z);
/* einfach */
/* Schreiben Sie eine Funktion die 2 Pointer auf Arrays von char (Strings) erwartet. */
/* Die Funktion soll alle Vorkommen vom letzten Zeichen des 1. Parameters im 2. Parameter finden und die haeufigkeit zurueckgeben */
  




/* Schreiben Sie eine Methode normalize() die einen Zeiger auf ein char erwartet und alle vorkommen von mehr als einem Leerzeichen oder Tab hintereinander durch je ein Leerzeichen ersetzt. */
  /*   aus: aab bbba\t ababab ab wird: aab bbba ababab ab */

/* aufwaendiger */
  
  /* Das struct list sei gegeben. Schreiben Sie eine Funktion f() die ein Pointer auf eine Liste und einen Zeiger auf eine Funktion func erwartet die ein int zurueck gibt und einen String erwartet. */
  /*   f() soll eine Liste zurueck geben die alle elemente der uebergebenen Liste enthaelt die fuer die die Funktion func nicht 0 ergibt. */
  /*   Schreiben sie eine weitere Funktion filter() die die vorige Funktion f() benutzt und nur Elemente die kleiner als 8 sind zurueck gibt. */
  /*   Sie duerfen fuer f() strcpy und fuer filter()  strlen benutzen. */

    /* Realisieren sie einen binaeren suchbaum. es soll methoden geben zum einfuegen, loeschen, element herausholen */

}
int main(void)
{
  /* definiere(); */
  bit();
  funktionen();
  return 0;
}
